// Classificator.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include "Classificator.h"

#include "dibapi.h"
#include "hsr_core.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

#define DATABASE_NAME _T("hsr.db")

// The one and only application object

CWinApp theApp;

using namespace std;

int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
	int nRetCode = 0;
	CFile file;

	// initialize MFC and print and error on failure
	if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0))
	{
		// TODO: change error code to suit your needs
		_tprintf(_T("Fatal Error: MFC initialization failed\n"));
		nRetCode = 1;
	}
	else if (argc < 2)
	{
		_tprintf(_T("Fatal Error: please supply file name\n"));
		nRetCode = 2;
	}
	else if (!file.Open(argv[1], CFile::modeRead))
	{
		_tprintf(_T("Fatal Error: couldn't open file: %s\n"), argv[1]);
		nRetCode = 3;
	}
	else 
	{
		Database database(DATABASE_NAME);

		HDIB dib = ReadDIBFile(file);
		file.Close();

		BYTE* lpS = (BYTE*)::GlobalLock((HGLOBAL)dib);
		BYTE* lpSrc = (BYTE*)::FindDIBBits((LPSTR)lpS);
		DWORD dwWidth  = ::DIBWidth((LPSTR)lpS);
		DWORD dwHeight = ::DIBHeight((LPSTR)lpS);
		DWORD w=WIDTHBYTES(dwWidth*8);

		Contour contour;
		if (!contour_extract(contour, dwWidth, dwHeight, w, lpSrc))
		{
			_tprintf(_T("Error: couldn't extract contour\n"));
			nRetCode = 4;
		}
		else
		{
			// transformata Fourier
			FourierSerie fourier_serie;
			for (unsigned int u = 0; u < 20; u++)
			{
				FourierTerm t = dft(contour, u);
				fourier_serie.push_back(t);
			}

			// calcul ultimii 20 termeni din seria Fourier
			for (unsigned int u = contour.size() - 20; u < contour.size(); u++)
			{
				FourierTerm t = dft(contour, u);
				fourier_serie.push_back(t);
			}

			// cautare distanta minima de la centroid la o clasa
			Centroid *centroid;
			CentroidList &centroid_list = database.centroid_list();
			unsigned int dist = 0;
			// cautarea distantei minime
			dist = centroid_search(centroid_list, fourier_serie, &centroid);
			if (0xFFFFFFFF == dist)
			{
				_tprintf(_T("FAIL: couldn't find suitable class for given centroid\n"));
			}
			else
			{
				_tprintf(_T("SUCCESS: Class '%s' found for given centroid, with distance '%d'\n"), centroid->label, dist);
				// afisare centroid clasificator
				CFile cenFile;
				cenFile.Open(_T("centroid.bmp"), CFile::modeWrite | CFile::modeCreate);
				HDIB cenDib = (HDIB)::CopyHandle((HGLOBAL)dib);
				BYTE* lpC = (BYTE*)::GlobalLock((HGLOBAL)cenDib);
				BYTE* lpCen = (BYTE*)::FindDIBBits((LPSTR)lpC);
				memset(lpCen, 255, w * dwHeight);
				// deseneaza centroidul clasificator
				for (unsigned int k = 0; k < 1000; k++)
				{
					Point p = idft(centroid->serie, k);
					lpCen[p.second*w+p.first] = 0;
				}
				SaveDIB(cenDib, cenFile);
				::GlobalUnlock((HGLOBAL)cenDib);
			}
			
			// afisare silueta din inversa DFT
			CFile dstFile;
			dstFile.Open(_T("invDFT.bmp"), CFile::modeWrite | CFile::modeCreate);			
			HDIB dstDib = (HDIB)::CopyHandle((HGLOBAL)dib);			
			BYTE* lpD = (BYTE*)::GlobalLock((HGLOBAL)dstDib);			
			BYTE* lpDst = (BYTE*)::FindDIBBits((LPSTR)lpD);			
			memset(lpDst, 255, w * dwHeight);			
			// reface imaginea din inversa DFT
			for (unsigned int k = 0; k < contour.size(); k++)
			{
				Point p = idft(fourier_serie, k);
				lpDst[p.second*w+p.first] = 0;
			}			
			// salveaza imaginea in fisier
			SaveDIB(dstDib, dstFile);			
			::GlobalUnlock((HGLOBAL)dstDib);			

			// curatare si finalizare
			fourier_serie.clear();
			contour.clear();

			::GlobalUnlock((HGLOBAL)dib);

			nRetCode = 0;
		}
	}

	return nRetCode;
}
